Skip to content

fix: resolve the P2 issues - #185

Merged
erkamyaman merged 18 commits into
santoshyadavdev:mainfrom
erkamyaman:fix/p2-issues
Sep 30, 2026
Merged

erkamyaman merged 18 commits into
santoshyadavdev:mainfrom
erkamyaman:fix/p2-issues

Conversation

@erkamyaman

Copy link
Copy Markdown
Collaborator

Fixes the open P2 issues from the September sweep, with tests for each fix and docs updated to match. Based on #184 (the P1 fixes), so review and merge that first.

Closes #85
Closes #86
Closes #87
Closes #88
Closes #89
Closes #90
Closes #91
Closes #92
Closes #93
Closes #94
Closes #95
Closes #96
Closes #97
Closes #98
Closes #99
Refs #100
Closes #101
Refs #102
Closes #105
Closes #106
Closes #107
Closes #108
Closes #109
Closes #110
Closes #111
Closes #112
Closes #113
Closes #114
Closes #115
Closes #116
Closes #117
Closes #118
Closes #119
Closes #121
Closes #122
Closes #123
Closes #124
Closes #125
Closes #126
Closes #127
Refs #128
Closes #129
Closes #130
Closes #131
Closes #132
Closes #133
Closes #134
Closes #135
Closes #136
Closes #137
Closes #138
Closes #139
Closes #140
Closes #141
Closes #142
Closes #143
Closes #144
Closes #145
Closes #146
Closes #147
Closes #148
Closes #149
Closes #150
Closes #151
Closes #152
Closes #153
Closes #154
Closes #155
Closes #156
Closes #158
Closes #159

Forms

SSR and HTTP

Injectors

NgRx

  • NgRx store: keyboard focus is lost when opening or closing the Restore confirmation #88: Cause: opening the Restore confirmation removed the focused button, and Cancel or Restore removed the group again, so focus fell to body. message was only ever set, never cleared. Fix: opening now focuses Cancel inside the labelled group, Cancel or Escape (which also calls preventDefault so the popup stays open) returns focus to Restore this state, restore keeps the P1 focus on the State tree or Back to latest, and selectPage, selectStore and selectEntry clear message.
  • NgRx store log shows no change for actions that touch array items past 100 or keys past 100 #118: Cause: the classic log diffed two serialize() snapshots, which keep only the first 100 items or keys, so changes past that limit looked like no change. Fix: logClassic keeps the previous raw state and falls back to referenceDiff on live values when the serialized diff is empty but the state reference changed. This matches the signal store path.
  • NgRx store: show where each action came from #119: Feature: while attached, the collector wraps Store.dispatch and Store.next and tags each action in a WeakMap as dispatch, effect (Store.next) or reactive. For reactive, it wraps the function given to dispatch(fn). stop puts the original methods back. The log entry has an origin, the panel shows it as a badge and an Origin row, and the ngrx-store resource description and docs are updated.
  • Test the classic @ngrx/store collector against the real library and cover it in the demo #134: Feature: adds @ngrx/store and @ngrx/store-devtools ^22.0.1 as root devDependencies. A real-library TestBed suite covers detection by class name, the action log with origins, restore with and without DevTools, maxAge eviction, dispatch while paused, the ActionsSubject fallback and giving up after 5 misses. A real-Angular test covers a component-scoped signalStore and a signalState field. The demo gets a Lab page at /examples/store with a spec.

Signals

  • Signals: value and history scroll boxes have no tabindex, and the change count is announced on every change #89: Cause: the value
     and the history 
      scroll but had no tabindex, and the history summary was aria-live, so it was read out again on every change. Fix: both boxes (and the new resource params, value and error boxes) now have tabindex="0", a label (role=region with aria-label, or aria-labelledby on the list) and a focus ring (m.focus-ring(-2px)). aria-live is removed from the summary.
    1. #117: Cause: on Angular 20.0 the graph nodes have no ids, so every node became "undefined" and graphKey never changed. Fix: a graph whose nodes lack ids now comes back as { unsupported: true }. The panel shows the source scan with the note "The live signal graph needs Angular 20.1 or later", and inspect-signals says the same. The DI empty state, signals.md, injectors.md, configuration.md, overlay.md, components.md and config.ts now give one minimum (Angular 20, and 20.1 for the live signal graph).
    2. #131: Cause: the collector only ever passed component-host injectors to ng.ɵgetSignalGraph. Fix: the collector finds the root and route environment injectors through ɵgetInjectorResolutionPath and pushes them as environments. The target { env } collects an R3Injector graph with the same node, edge and history code. The "Graph of" picker now lists Root services and Route: path entries. inspect-signals accepts root, /path, Route: path or an injector id: it switches the page and waits up to 1.5s for the graph. The demo TravelStore gets a root persistSaved effect.
    3. #132: Cause: the Resource#name.* internals and the httpResource extras reached the panel as separate nodes with no link between them, and linkedSignal state had no value. Fix: the new signal-resources.ts groups these nodes by label and edges into resources (status, isLoading, params, value, error, statusCode, nodeIds). It reads the resource's state without calling it and numbers unnamed resources. Status changes go into the history. The panel shows a Resources section with status tags, a status history and a toggle for the internal signals. inspect-signals and the signal-graph resource return the grouped view.
    4. #138: Cause: a linkedSignal value came from any instance getter whose name matched the node label, and the getter was called. Fix: a field's value is used only when exactly one field's SIGNAL node has the same name and version === epoch, and exactly one graph node has that label and epoch. The stored node.value is read only when the node is not dirty, so no user computation runs.
    5. #154: Cause: the badge and the summary counted the history list, which is capped at 50, and 400+ node graphs were cut with no notice. Fix: signal-history keeps a total per node and resource, gaps between capped writes included, and the overlay sends it as changes. The panel shows "N changes recorded, showing the last 50", uses correct plurals and no longer says "0 changes" over the initial entry. When the graph is cut, it sends nodeCount and the panel shows "Showing 400 of N signals".

Components

  • Agents cannot pick a component to read its live detail; highlight never sets the selection #91: Only the panel's select-component set the page's componentTarget, and highlight used the first findComponents hit without saying how many matched. highlight now also selects the instance (shared selectedId plus inspect-component-in-page) and lists every matching id. A new read tool, ng-devtools:inspect-component, selects the instance, waits up to 3 s for the page to report it and returns the live detail. Both tools take an optional pageId, and the panel follows a selection made elsewhere.
  • Components: show the selected component's own properties, not only inputs #109: componentDetail only read the keys in getDirectiveMetadata().inputs. A new detail.properties field lists own enumerable fields that are not inputs, outputs, methods, ngContext or injected services (matched by the dep.value that ɵgetDependenciesFromInjectable returns). Signals are unwrapped and resources become {status, value, error}. Values are capped with MAX_PROPS and VALUE_LIMITS and redacted through serializeNamed. The panel gets a Properties block, and the resource and tool descriptions mention the field.
  • Inspect @defer blocks and incremental hydration state with ng.ɵgetControlFlowBlocks #116: The only defer data was a page-wide count. A new collector (defer-blocks.ts) calls ng.ɵgetControlFlowBlocks, or ng.ɵgetDeferBlocks as a fallback, on each Angular root. For each block it records the owner, state, hydration, triggers, loading and placeholder config, root element ids and state-change or hydratedAt times, and ids stay stable. The list goes into the component tree report. The panel shows a Defer blocks list (hidden when empty or when the util is missing), and a new ng-devtools:defer-blocks tool flags blocks that failed or are stuck on their placeholder. A /examples/defer demo page was added, with withIncrementalHydration() turned on.
  • Components and Dashboard show the newest reporting tab instead of the inspected page #143: Without ?pageId, page() picked the newest reportedAt, so keepalive pushes swapped tabs, and the Dashboard read the global tree and graph. Components now keeps the shown page in a linkedSignal (picked page, then host page, then the previous page, then the newest) and adds a Page picker labelled with the url and title the overlay now reports. The Dashboard Injectors and Signals cards read pages[pageId] when a page id is known and no longer fall back to another page.
  • Components filter shows no match count, and the live count announces app churn to screen readers #144: The count always showed the total inside an aria-live region, which announced app churn. filterTree now counts matching nodes only, the count reads 'N of M' while filtering, it is no longer a live region, and a separate status region announces the result only from setFilter.
  • Components: a destroyed selected component clears the detail pane silently and drops keyboard focus #145: selectedNode went null while selectedId was kept, focus fell to body and the page kept componentTarget. reconcileSelection now drops a selection that left the tree (skipped when the tree is truncated) and sends select-component with a null id. The panel shows 'The selected component was destroyed' and announces it, and focus moves to the nearest remaining row (the next one, else the previous one or the parent).
  • Components: pick an element on the page to select its component #146: Only the extension could go from the page to a component. A new startComponentPick (component-pick.ts) highlights the host under the pointer and selects the host of the clicked element. It ignores the popup, fades the floating panel through a data-picking attribute, and stops on Escape, cancel() or a 15 s timeout. It is wired through request-component-pick, component-pick, component-pick-result and cancel-component-pick. The panel has a Pick component on page / Cancel pick button, and Escape cancels from the panel too.

Overlay and popup

  • Floating panel is not kept on screen and can only be dragged with a mouse #111: Cause: the toolbar drag only listened to mouse events, had no touch-action: none and gave no way to move the panel without dragging. The P1 branch already clamped the restored position and size. Fix: the toolbar drag now uses pointer events with capture and touch-action: none and ignores the dock and close buttons, and a double click on the toolbar resets the panel to its default place. Tests cover off-screen restore plus resize, touch drag, button presses that should not drag, dblclick reset and dock switching.
  • Page highlight and floating button are hidden behind dialogs, popovers and CDK overlays in the top layer #121: Cause: the highlight box, launcher and panel were fixed elements with a z-index, so top-layer dialogs, popovers and CDK overlays painted over them. Fix: all three are now popover="manual" and shown with showPopover() when the API exists (the z-index stays as the fallback). The launcher and panel are shown again on any document toggle-open event, except for a :modal dialog.
  • Page highlight skips SVG hosts and draws an empty box for display: contents, hidden or off-screen hosts #122: Cause: highlight-in-page only accepted HTMLElement and drew the raw getBoundingClientRect. Fix: highlighting moved to page-highlight.ts. It accepts any Element, uses the union of the children's boxes for an empty rect, draws nothing when that is empty too (and returns false), and scrolls into view with block 'nearest' when the request has reveal: true. The agent highlight tool and the Pipes chip click send that flag.
  • Pages drop out of the panel when their tab is in the background or refreshMs is above 7500 #123: Cause: keepalives skipped a tick when elapsed < 8000 ms, so any refreshMs above 7500 reported only every ~16 s, past the 15 s TTL. Hidden tabs were throttled below the TTL too. Fix: a new keepaliveDue(sentAt, tickMs) sends when the next tick would be too late, and TTLs are shared through rpc/page-ttl.ts. Pages now pause collection on visibilitychange and send report-page-visibility (repeated every 60 s while hidden), and the server keeps hidden pages until 5 minutes pass without that signal. The panel says 'Tab in background, showing the last data.'
  • Pressing Escape to clear a filter box also closes the popup panel #127: Cause: the popup closed on any Escape from the frame that was not defaultPrevented, and search boxes clear on Escape without preventDefault (native type=search does the same). Fix: a capture-phase listener on the frame document marks Escape events whose target is a type=search input with text, and the close handler ignores them. Test: Escape in a filled search box clears it and keeps the panel open, and a second Escape closes it.
  • Selected inspector tab resets to Dashboard on every page reload in the extension and popup #152: Cause: the tab was only restored from #tab=, and the extension and popup reload the panel without a hash. Fix: the new app/src/tab-memory.ts saves the tab in sessionStorage per view (inside try/catch) when the user switches tabs. On load the hash wins, otherwise the saved tab is used, and a tab that is not available falls back to Dashboard.

Router

  • navigate waitFor: 'stable' is a fixed 300 ms delay, not app stability #96: Cause: waitFor: 'stable' waited a fixed 300 ms after the navigation ended. Fix: new waitForStable() in router-actions.ts waits on the Router's root PendingTasksInternal (the same signal ApplicationRef.whenStable() reads), within the 10s WAIT_MS. The result now includes stable: true, stable: false with a note, or stable: 'unknown'. The tool schema also describes waitFor now.
  • Router detection fails on Angular 20.0 to 20.3.4, and CI never tests the declared peer range #100 (partly): Partly fixed. Cause confirmed: ɵgetRouterInstance first ships in @angular/router 20.3.5 (checked with npm pack of 20.3.4 and 20.3.5). Fix: Analog's routerOf now falls back to findRouters (the injector-provider lookup), setupKind reports 'unknown' when the util is missing on versions below 20.3.5 (new publishesRouterUtil), and the docs name the tested Angular and Node versions.
  • DevTools Lab: add a route scenario that triggers router loop detection #102 (partly): Cause: the Routes lab had no loop case. Fix: added loop-a/loop-b routes whose guards redirect to each other five times and then to summary?from=loop (a bounded module counter), a Guard loop link, RenderMode.Client entries for both routes, a root-app spec, and docs in demo-apps.md and router.md.
  • Probe in app runs a full navigation when a canMatch guard redirects #128 (partly): Cause: probe only tracked its own navigation id, so when canMatch redirected (UrlTree, RedirectCommand, or the error handler) the follow-up navigation ran to completion. Fix: after a Redirect cancel, probe takes over the next navigation id and aborts it at NavigationStart, marks both records as probes, and returns redirectedTo. The panel message and the tool description report this too.
  • Router instrumentation: class guards and resolvers shared by several routes always report the first route #129: Cause: class guard and resolver wrappers sit on the shared prototype and fixed the first route's path (and resolve key) when they were created. Fix: a module WeakMap maps each route config to its path, and the wrapper works out the route (and resolve key) from its run arguments (Route for canMatch/canLoad, snapshot.routeConfig otherwise, walking up to the declaring route for canActivateChild).
  • Router setup detection: initialNavigation and withDebugTracing() are wrong for provideRouter apps, and nothing tests it against a real Router #130: Cause: detectSetup only read router.options and missed the INITIAL_NAVIGATION token, the withDebugTracing initializer and platform navigation. Testing against a real Router also showed the scroller was never detected (its token is an InjectionToken, not a RouterScroller class). Fix: read INITIAL_NAVIGATION from the explicit providers, find the tracing initializer in the injector records, add a platformNavigation feature (NavigationStateManager), and fall back to the 'Router Scroller' token. Real-Router tests now cover every with* feature and the forRoot options.
  • Router Lint shows an all-clear when it could not check, and stops re-running after 50 navigations #151: Cause: router-lint returned [] when it could not check, the panel turned RPC failures into [], re-runs were keyed on the capped navigations.length, and every re-run replaced the list and could be overwritten by a stale answer. Fix: the server returns {checked:false, reason} or {checked:true, findings}. The panel shows 'No checks ran' with events-only or no-config wording, and an error with Retry. Re-runs are keyed on the last navigation's id and outcome, findings stay visible during automatic re-runs, and a sequence token drops stale answers.

Analog

  • Analog demo: login and register give no field errors, and checkout shows errors before any input #101: Cause: login and register had no per-field errors, aria-invalid, aria-describedby or invalid style, and checkout showed errors before any touch. Fix: per-field errors after touch or submit with aria-invalid and aria-describedby, a register status line, checkout errors gated on touched(), and an --error token with an invalid border (light #b91c1c, dark #f87171 for AA contrast). Invalid states are still reachable for the Forms inspector.
  • Analog load() preview redacts normal keys like author and passengers #105: Cause: redact() in analog-runtime.ts hid any key containing a secret substring (auth, pass, card and so on), so author and passengers were hidden. Fix: it now uses the whole-word isSecretKey from analog-server-log.ts, plus the custom redaction.secretNames, the same check server call previews use.
  • Analog render modes: last request never matches dynamic pages, routeRules match by prefix, and most route rules are ignored #106: Cause: last-request rows were keyed by the real URL but looked up by pattern, /x/** matched by string prefix, and only ssr: false route rules were read. Fix: requests are matched to rows with explainUrl, matching follows Nitro (/x/** covers /x and below, * is one segment, the most specific rule wins), every rule kind is parsed (ssr, prerender, isr, swr, cache, redirect, Cache-Control) and cited as the reason, Cached and Redirect modes are new, and prerender: true rules feed the Prerender plan.
  • Analog: form action submissions are logged as load() fetches #107: Cause: classify() mapped every method on /_analog/pages to load. Fix: a new action kind for non-GET/HEAD requests, with a success, redirect (redacted Location), invalid (X-Analog-Errors, redacted preview) or error outcome. It is in the Server filter, analog-server-calls and its kind enum, and duplicateLoads() now pairs GET loads only.
  • Analog: show server functions by name, including SSR calls, and stop false lint warnings for them #108: Cause: the scan only looked at page .server.ts files for load/action, calls showed opaque ids, SSR calls skip HTTP, and __analog_fn_ seeds were unlabeled. Fix: scan every src/**/*.server.ts for serverFn exports with Analog's sha256 id and method, show names in the Server list, analog-server-calls and payload labels, record SSR reads from their TransferState seeds in the page HTML, flag a seeded read called again after hydration (lint fn-fetched-twice, a callout, notes), stop the two false warnings, and add the analog-server-functions MCP tool plus a Server functions table.
  • Analog Routes and Server tabs: Test a URL shows stale results, and the request playground has no pending state #141: Cause: the Test a URL callout showed the live input text over an old result, and failures and empty input did nothing. send() kept the old response and left Send enabled. Fix: the result now stores the URL it explains, shows empty-input and RPC errors, and has an Explaining state. The playground has a sending state that clears the old response and turns Send off. Send also stays off for POST/PUT/PATCH/DELETE until the checkbox is ticked, with a hint that points to it.
  • Analog lint cards hide the per-finding message, so hydration errors and duplicate files lose their details #142: Cause: lintCards kept only file and path for each finding and dropped message. Fix: each card item keeps the per-finding message and shows it (skipped for rules whose message only repeats the summary), and identical items are deduped.

Pipes

CLI, config and security

  • Agent tools pick the browser tab inconsistently and fall back silently on a wrong page id #90: Cause: each live tool picked the page its own way. highlight and inspect-signals had no page argument, findComponents walked pages oldest first, and an unknown pageId/page fell back silently or blamed stdio. Fix: a shared page argument (rpc/pages.ts PAGE_ARGUMENT, inspect-providers keeps pageId as an alias), one unknownPageText message that lists the reporting pages newest first (used by the router noPage, forms, highlight, inspect-signals, inspect-providers and navigate), names resolved on the newest page with a note for other matches, and a new list-pages tool.
  • Standalone CLI and stdio MCP server can't take any devtools config #93: Cause: bin.mjs passed the default export (always the defaults) to createCac, so mcp registered every tool, including page-only and write tools. Fix: a new createNgDevtoolsCli() in cli.ts adds --config <file> / NG_DEVTOOLS_CONFIG / ng-devtools.config.json and --read-only to dev, build and mcp, and passes the config through createNgDevtools(). Its new pageTools host option drops the tools listed in PAGE_AGENT_ENTRIES from mcp.
  • Standalone CLI has no way to set the project folder, and scans from the wrong folder return empty data silently #133: Cause: every scan reads ctx.cwd = process.cwd(), and nothing could change it. Fix: --root <dir> / NG_DEVTOOLS_ROOT changes into the folder before the server starts and refuses a missing folder. If the folder has no angular.json and no package.json that depends on @angular/core, it prints a warning on stderr.
  • Vite plugin: allowedOrigins entries with a trailing slash, path or uppercase host never match but still turn on the one-time code #136: Cause: isAllowedHubOrigin compared raw allowedOrigins entries with the browser origin, while allowsRemoteOrigins still counted them. Fix: new normalizeAllowedOrigins() reduces each entry to new URL(entry).origin once, warns through server.config.logger when it changes or drops an entry, and feeds the same list to both checks. A new blockedOriginReporter warns once per refused origin, for HTTP and WebSocket.
  • Warn at startup when the devtools config has unknown keys, wrong types or clamped limits #137: Cause: resolveNgDevtoolsConfig() silently dropped unknown keys and wrong types and clamped limits. Fix: new ngDevtoolsConfigProblems() / ngDevtoolsConfigWarning() list unknown keys (with a "did you mean"), wrong types (with the value used instead) and clamped limits. createNgDevtools() prints one [ng-devtools] warning. configFromConnection stays silent.
  • ng-devtools CLI prints version 0.0.0, prints no URL on start, and shows a stack trace for an unknown flag #139: Cause: devframe's createCac hardcodes version 0.0.0, bin.mjs passed no onReady, and parse errors were unhandled. Fix: createNgDevtoolsCli() sets cli.globalCommand.versionNumber from package.json. It prints the version, panel URL and MCP URL on ready, plus a note when port 9999 was taken. It registers a real dev command, rejects unknown positionals, and catches every error as one [ng-devtools] line with exit code 1.
  • Redaction rules differ across inspectors: mask and unmask lists, token scrubbing and secret words #159: Cause: NgRx, nested form values, Signal Forms placeholders, secretInside/keepSecrets and Analog called isSecretKey (or their own regexes) and ignored mask/unmask, the NgRx serializer skipped redactMessage, and Analog had its own word list. Fix: one isRedactedKey() (the built-in words, secretNames, mask and unmask) used everywhere, one merged word list (adds cookie, authorization, jwt, sessionId, sessionKey), and redactMessage on NgRx strings and Error messages.

Performance and limits

  • Hydration warning capture makes console.warn and console.error throw on some arguments #112: Cause: captureHydrationWarnings in http.ts built the log text with String(a) before calling the original console method, so a null-prototype object or a throwing toString threw before the call. Fix: each argument is turned into text in a guarded textOf(), the whole parse is in try/catch, and the original method always runs.
  • Show when a timeline has dropped old entries at its limit #153: Cause: the HTTP, navigation, forms and NgRx timelines trimmed at their limits and reported nothing. Fix: each collector or merge counts what it drops (HttpPage.dropped and HttpState.serverDropped, RouterReport.dropped, FormsState.dropped per page, NgrxPage.dropped from the first kept seq). A shared app-limit-note shows 'Showing the latest N ... Raise limits.X' with a docs link on all four timelines, and explain-navigation and form-history add the same note.
  • Overlay keepalives resend full HTTP call lists and trees, and every push rebroadcasts the whole shared state #155: Cause: components, injectors, signals and HTTP resent their full data every 8 s, HTTP resent every call on each change, and push-http rebroadcast all TransferState payloads in the 'http' state. Fix: unchanged data now sends ping-component-tree, ping-injector-tree, ping-signal-graph or ping-http, which update reportedAt on the server without a mutate. HTTP sends the full call list only with the payload and after that only new calls (full: false). Payloads moved to a separate 'http-payloads' shared state that changes only when a payload arrives or a page goes away. Overlay FAQ and components docs updated.
  • Record change detection cycles and time per component using the existing profiler hook #156: Cause: the profiler only debounced refreshes, and the forms render counter registered its own profiler without the v20 guard. Fix: change-detection.ts now has one guarded profiler hub (addProfilerListener, never setProfiler(null)) that the refresh scheduler, countRenders and a new opt-in recorder share. cd-recorder.ts records cycles (start, duration, sync passes, per-component checks and self time, and the output that ran before the tick) with a new limits.cdCycles cap and totals per component. It is exposed through push-, ping-, forget- and request-change-detection-record, a 'change-detection' shared state, a Record, Stop and Clear section with a cycle list and slowest-components table in the Components tab, check-count badges on tree rows, and an ng-devtools:change-detection agent tool.

CI

  • Add unit tests and an automated axe check for the devtools panel in CI #97: The panel had no tests and axe only ran by hand, which hid a bug: Select.move() clamped to the list end and landed on a disabled option. Fixed move() to step to the next enabled option only. Added a Vitest setup for app/ (pnpm test:panel, 32 tests) and an axe CI job (pnpm test:axe, all tabs and hub views, light and dark). The job found a duplicate region landmark on Routes, now fixed.
  • Analog demo is not type-checked, and its tsconfig fails on the package source #98: Two causes. The demo's tsconfig rejected the package's .ts import paths (TS5097). Also, nothing in the demo program imports devframe itself, so TS never loaded it as the augmentation target (TS2664). Fixed with rewriteRelativeImportExtensions in examples/analog/tsconfig.app.json and import type {} from 'devframe' in types.ts. Widened the include to src/server/**, so API routes are checked too, and added the demo's ngc check to pnpm typecheck.
  • CI does not type-check panel templates, so template errors in app/ pass every check #99: pnpm typecheck ran plain tsc on app/, which never reads templates. It now runs ngc -p app/tsconfig.json --noEmit, and app/tsconfig.json turns on strictTemplates (it passes with 0 errors).

Left open

Checks

Notes for review

  • test:devtools now runs the package tests only; the panel tests and the axe check are separate scripts, and CI runs all three
  • @ngrx/store and @ngrx/store-devtools are new dev dependencies, and the demo has a new /examples/store page

Fixes wrong data, leaked values and broken setups found in the issue
sweep: signal history, NgRx restore, forms selects, router labels and
large route configs, pipe and Analog redaction, HTTP fault rules,
Analog hydration and Nx routes, build-meta, mount path, popup server
detection, extension panel after worker idle, Vite restart, HTTPS,
WebSocket guard and base handling, hub restarts, static report scans
and the build output guard. Docs are updated to match.

Fixes santoshyadavdev#63, santoshyadavdev#64, santoshyadavdev#65, santoshyadavdev#66, santoshyadavdev#67, santoshyadavdev#68, santoshyadavdev#69, santoshyadavdev#70, santoshyadavdev#71, santoshyadavdev#72, santoshyadavdev#73, santoshyadavdev#74, santoshyadavdev#75, santoshyadavdev#76, santoshyadavdev#77, santoshyadavdev#78, santoshyadavdev#79, santoshyadavdev#80, santoshyadavdev#81, santoshyadavdev#82, santoshyadavdev#83, santoshyadavdev#84
Rebuilds extension/ui so the bundled panel matches the app changes
for the NgRx restore banner, router truncation and server detection.
Restoring a state or pressing Back to latest removed the focused
control, so focus fell to the page body. Focus now moves to the Back
to latest button or the State tree, and the banner no longer repeats
the status message.
At 360px the floating panel stayed 720px wide and cut off the no
server message and the toolbar. The panel is now clamped to the
window, the message scrolls, is announced through a status line and
has a heading, and the setup link says it opens a new tab.
Rebuilds extension/ui so the bundled panel includes the store
inspector focus fix.
Fixes wrong or missing data, accessibility gaps, redaction gaps and
limits across forms, SSR and HTTP, injectors, NgRx, signals,
components, overlay, router, Analog, pipes, the CLI and config, and
adds panel tests and an axe check to CI. Also adds the features the
P2 issues asked for: defer blocks, element picking, component
properties, action origins, resource entries and change detection
recording. Docs are updated to match.

Refs santoshyadavdev#100, santoshyadavdev#102, santoshyadavdev#128
Fixes santoshyadavdev#85, santoshyadavdev#86, santoshyadavdev#87, santoshyadavdev#88, santoshyadavdev#89, santoshyadavdev#90, santoshyadavdev#91, santoshyadavdev#92, santoshyadavdev#93, santoshyadavdev#94, santoshyadavdev#95, santoshyadavdev#96, santoshyadavdev#97, santoshyadavdev#98, santoshyadavdev#99, santoshyadavdev#101, santoshyadavdev#105, santoshyadavdev#106, santoshyadavdev#107, santoshyadavdev#108, santoshyadavdev#109, santoshyadavdev#110, santoshyadavdev#111, santoshyadavdev#112, santoshyadavdev#113, santoshyadavdev#114, santoshyadavdev#115, santoshyadavdev#116, santoshyadavdev#117, santoshyadavdev#118, santoshyadavdev#119, santoshyadavdev#121, santoshyadavdev#122, santoshyadavdev#123, santoshyadavdev#124, santoshyadavdev#125, santoshyadavdev#126, santoshyadavdev#127, santoshyadavdev#129, santoshyadavdev#130, santoshyadavdev#131, santoshyadavdev#132, santoshyadavdev#133, santoshyadavdev#134, santoshyadavdev#135, santoshyadavdev#136, santoshyadavdev#137, santoshyadavdev#138, santoshyadavdev#139, santoshyadavdev#140, santoshyadavdev#141, santoshyadavdev#142, santoshyadavdev#143, santoshyadavdev#144, santoshyadavdev#145, santoshyadavdev#146, santoshyadavdev#147, santoshyadavdev#148, santoshyadavdev#149, santoshyadavdev#150, santoshyadavdev#151, santoshyadavdev#152, santoshyadavdev#153, santoshyadavdev#154, santoshyadavdev#155, santoshyadavdev#156, santoshyadavdev#158, santoshyadavdev#159
Rebuilds extension/ui so the bundled panel includes the P2 panel
changes.
@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 195 files, which is 45 over the limit of 150.

To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to Team to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Check out review usage here.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Essentials

Run ID: e890b55d-8122-45d9-91b0-ccc836265b08

📥 Commits

Reviewing files that changed from the base of the PR and between fbae46c and 1edc1a4.

⛔ Files ignored due to path filters (3)
  • extension/ui/assets/index-CT4NGk62.js is excluded by !**/assets/index-[0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-].js
  • extension/ui/assets/index-DBeQs79F.js is excluded by !**/assets/index-[0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-][0-9a-z_-].js
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (195)
  • .claude/skills/devtools-ui/SKILL.md
  • .claude/skills/devtools-verify/SKILL.md
  • .github/PULL_REQUEST_TEMPLATE.md
  • .github/workflows/ci.yml
  • app/src/__tests__/base-url.test.ts
  • app/src/__tests__/dashboard-cards.test.ts
  • app/src/__tests__/format.test.ts
  • app/src/__tests__/forms-panels.test.ts
  • app/src/__tests__/hub-dock-sync.test.ts
  • app/src/__tests__/select.test.ts
  • app/src/__tests__/store-inspector.test.ts
  • app/src/app.ts
  • app/src/base-url.ts
  • app/src/live-pages.ts
  • app/src/pages/analog-inspector.ts
  • app/src/pages/cd-recording.ts
  • app/src/pages/component-tree-state.ts
  • app/src/pages/component-tree.ts
  • app/src/pages/dashboard.ts
  • app/src/pages/di-inspector.ts
  • app/src/pages/forms-field-detail.ts
  • app/src/pages/forms-inspector.ts
  • app/src/pages/forms-report.ts
  • app/src/pages/network-inspector.ts
  • app/src/pages/pipes-inspector.ts
  • app/src/pages/route-inspector.ts
  • app/src/pages/route-lint.ts
  • app/src/pages/route-timeline.ts
  • app/src/pages/route-tree.ts
  • app/src/pages/router-types.ts
  • app/src/pages/signal-inspector.ts
  • app/src/pages/store-inspector.ts
  • app/src/pages/store-types.ts
  • app/src/tab-memory.ts
  • app/src/test-setup.ts
  • app/src/ui/limit-note.ts
  • app/src/ui/select.ts
  • app/tsconfig.json
  • app/vitest.config.ts
  • apps/docs/src/content/agents/mcp-server.md
  • apps/docs/src/content/agents/resources.md
  • apps/docs/src/content/agents/tools.md
  • apps/docs/src/content/contributing/demo-apps.md
  • apps/docs/src/content/contributing/development.md
  • apps/docs/src/content/getting-started/cli.md
  • apps/docs/src/content/getting-started/configuration.md
  • apps/docs/src/content/getting-started/installation.md
  • apps/docs/src/content/getting-started/overlay.md
  • apps/docs/src/content/getting-started/popup-and-hub.md
  • apps/docs/src/content/getting-started/vite.md
  • apps/docs/src/content/inspectors/analog.md
  • apps/docs/src/content/inspectors/components.md
  • apps/docs/src/content/inspectors/dashboard.md
  • apps/docs/src/content/inspectors/forms.md
  • apps/docs/src/content/inspectors/injectors.md
  • apps/docs/src/content/inspectors/ngrx-store.md
  • apps/docs/src/content/inspectors/pipes.md
  • apps/docs/src/content/inspectors/router.md
  • apps/docs/src/content/inspectors/signals.md
  • apps/docs/src/content/inspectors/ssr-http.md
  • apps/docs/src/content/security.md
  • bin.mjs
  • docs/contributing/coding-standards.md
  • examples/analog/src/app/pages/(auth)/login.page.ts
  • examples/analog/src/app/pages/(auth)/register.page.ts
  • examples/analog/src/app/pages/checkout.page.ts
  • examples/analog/src/styles.css
  • examples/analog/tsconfig.app.json
  • extension/ui/assets/browser-agent-rpc-BXhoSh1z-Cfmnc8tc.js
  • extension/ui/index.html
  • package.json
  • packages/ng-devtools/bin.mjs
  • packages/ng-devtools/src/__tests__/agent-tools.test.ts
  • packages/ng-devtools/src/__tests__/analog-inspector.test.ts
  • packages/ng-devtools/src/__tests__/analog-mcp.test.ts
  • packages/ng-devtools/src/__tests__/analog-runtime.test.ts
  • packages/ng-devtools/src/__tests__/analog-server-fns.test.ts
  • packages/ng-devtools/src/__tests__/analog-server-log.test.ts
  • packages/ng-devtools/src/__tests__/cd-recorder.test.ts
  • packages/ng-devtools/src/__tests__/cli-bin.test.ts
  • packages/ng-devtools/src/__tests__/cli.test.ts
  • packages/ng-devtools/src/__tests__/component-agent.test.ts
  • packages/ng-devtools/src/__tests__/component-pick.test.ts
  • packages/ng-devtools/src/__tests__/component-tree.test.ts
  • packages/ng-devtools/src/__tests__/config.test.ts
  • packages/ng-devtools/src/__tests__/defer-blocks.test.ts
  • packages/ng-devtools/src/__tests__/dom-walk.test.ts
  • packages/ng-devtools/src/__tests__/forms-collector.test.ts
  • packages/ng-devtools/src/__tests__/forms-instrument.test.ts
  • packages/ng-devtools/src/__tests__/forms-mcp.test.ts
  • packages/ng-devtools/src/__tests__/forms-tools.test.ts
  • packages/ng-devtools/src/__tests__/forms.test.ts
  • packages/ng-devtools/src/__tests__/http-cache-key.test.ts
  • packages/ng-devtools/src/__tests__/http-server.test.ts
  • packages/ng-devtools/src/__tests__/http.test.ts
  • packages/ng-devtools/src/__tests__/injector-tree.test.ts
  • packages/ng-devtools/src/__tests__/network-inspector.test.ts
  • packages/ng-devtools/src/__tests__/ngrx-collector.test.ts
  • packages/ng-devtools/src/__tests__/ngrx-mcp.test.ts
  • packages/ng-devtools/src/__tests__/overlay-config.test.ts
  • packages/ng-devtools/src/__tests__/overlay-visibility.test.ts
  • packages/ng-devtools/src/__tests__/page-highlight.test.ts
  • packages/ng-devtools/src/__tests__/page-visibility.test.ts
  • packages/ng-devtools/src/__tests__/panel-component-tree.test.ts
  • packages/ng-devtools/src/__tests__/panel-tab-memory.test.ts
  • packages/ng-devtools/src/__tests__/pipes-collector.test.ts
  • packages/ng-devtools/src/__tests__/pipes-pages.test.ts
  • packages/ng-devtools/src/__tests__/popup.test.ts
  • packages/ng-devtools/src/__tests__/redaction-config.test.ts
  • packages/ng-devtools/src/__tests__/router-actions-wait.test.ts
  • packages/ng-devtools/src/__tests__/router-forroot.test.ts
  • packages/ng-devtools/src/__tests__/router-mcp.test.ts
  • packages/ng-devtools/src/__tests__/router-setup-real.test.ts
  • packages/ng-devtools/src/__tests__/router-shared-guards.test.ts
  • packages/ng-devtools/src/__tests__/router-tools.test.ts
  • packages/ng-devtools/src/__tests__/signal-graph-real.test.ts
  • packages/ng-devtools/src/__tests__/signal-graph.test.ts
  • packages/ng-devtools/src/__tests__/signal-history.test.ts
  • packages/ng-devtools/src/__tests__/signal-resources.test.ts
  • packages/ng-devtools/src/__tests__/store-inspector.test.ts
  • packages/ng-devtools/src/__tests__/vite-auth.test.ts
  • packages/ng-devtools/src/analog-runtime.ts
  • packages/ng-devtools/src/analog-server-log.ts
  • packages/ng-devtools/src/cd-overlay.ts
  • packages/ng-devtools/src/cd-recorder.ts
  • packages/ng-devtools/src/change-detection.ts
  • packages/ng-devtools/src/cli.ts
  • packages/ng-devtools/src/component-pick.ts
  • packages/ng-devtools/src/component-tree.ts
  • packages/ng-devtools/src/config.ts
  • packages/ng-devtools/src/defer-blocks.ts
  • packages/ng-devtools/src/devframe.ts
  • packages/ng-devtools/src/dom-walk.ts
  • packages/ng-devtools/src/forms-actions.ts
  • packages/ng-devtools/src/forms-collector.ts
  • packages/ng-devtools/src/forms-instrument.ts
  • packages/ng-devtools/src/forms-privacy.ts
  • packages/ng-devtools/src/forms.ts
  • packages/ng-devtools/src/http-cache-key.ts
  • packages/ng-devtools/src/http-overlay.ts
  • packages/ng-devtools/src/http-payload.ts
  • packages/ng-devtools/src/http-redact.ts
  • packages/ng-devtools/src/http-rules.ts
  • packages/ng-devtools/src/http.ts
  • packages/ng-devtools/src/injector-tree.ts
  • packages/ng-devtools/src/ngrx-collector.ts
  • packages/ng-devtools/src/ngrx-shared.ts
  • packages/ng-devtools/src/overlay.ts
  • packages/ng-devtools/src/page-highlight.ts
  • packages/ng-devtools/src/pipes-collector.ts
  • packages/ng-devtools/src/popup.ts
  • packages/ng-devtools/src/router-actions.ts
  • packages/ng-devtools/src/router-setup.ts
  • packages/ng-devtools/src/router.ts
  • packages/ng-devtools/src/rpc/__tests__/get-pipes.test.ts
  • packages/ng-devtools/src/rpc/__tests__/get-providers.test.ts
  • packages/ng-devtools/src/rpc/__tests__/pipe-lint.test.ts
  • packages/ng-devtools/src/rpc/analog-register.ts
  • packages/ng-devtools/src/rpc/analog-scan.ts
  • packages/ng-devtools/src/rpc/analog-tools.ts
  • packages/ng-devtools/src/rpc/cd-tools.ts
  • packages/ng-devtools/src/rpc/component-tools.ts
  • packages/ng-devtools/src/rpc/forms-explain.ts
  • packages/ng-devtools/src/rpc/forms-tools.ts
  • packages/ng-devtools/src/rpc/get-pipes.ts
  • packages/ng-devtools/src/rpc/get-providers.ts
  • packages/ng-devtools/src/rpc/injector-tools.ts
  • packages/ng-devtools/src/rpc/ngrx-tools.ts
  • packages/ng-devtools/src/rpc/page-ttl.ts
  • packages/ng-devtools/src/rpc/pages.ts
  • packages/ng-devtools/src/rpc/pipe-explain.ts
  • packages/ng-devtools/src/rpc/pipe-lint.ts
  • packages/ng-devtools/src/rpc/pipes-tools.ts
  • packages/ng-devtools/src/rpc/router-config-tools.ts
  • packages/ng-devtools/src/rpc/router-tools.ts
  • packages/ng-devtools/src/signal-graph.ts
  • packages/ng-devtools/src/signal-history.ts
  • packages/ng-devtools/src/signal-resources.ts
  • packages/ng-devtools/src/timeline-limits.ts
  • packages/ng-devtools/src/types.ts
  • packages/ng-devtools/src/vite.ts
  • scripts/panel-axe.mjs
  • src/app/app.config.ts
  • src/app/app.routes.server.ts
  • src/app/examples/defer-example.ts
  • src/app/examples/defer-note.ts
  • src/app/examples/examples-overview.ts
  • src/app/examples/examples.routes.ts
  • src/app/examples/examples.ts
  • src/app/examples/route-guards.spec.ts
  • src/app/examples/route-guards.ts
  • src/app/examples/routes-example.ts
  • src/app/examples/store-example.spec.ts
  • src/app/examples/store-example.ts
  • src/app/travel/travel.store.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added area: panel The devtools panel app (app/) area: package The ng-devtools package (packages/ng-devtools) area: extension The Chrome extension area: demo The demo apps area: agents MCP server, agent tools and resources area: docs The documentation site area: ci Workflows, hooks and repository tooling labels Sep 30, 2026
@nx-cloud

nx-cloud Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 1edc1a4

Command Status Duration Result
nx affected -t test build ✅ Succeeded 2s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-09-30 22:40:22 UTC

@erkamyaman erkamyaman self-assigned this Sep 30, 2026
@erkamyaman
erkamyaman marked this pull request as ready for review September 30, 2026 20:05
Canonicalizes paths in the build output guard, keeps select writes on
the option-matching path for multiple and object-valued selects,
redacts text before clipping it, counts left-out child routes and
warns about truncation in every router tool mode, stops treating an
Nx root Analog dependency as proof an app uses Analog, finds the Nx
workspace output on its own, replaces any types in build-meta, checks
values before reusing a signal history binding, and keeps focus after
restoring the newest NgRx action.
Rebuilds extension/ui for the store inspector focus change.
Brings in the review fixes from santoshyadavdev#184. Keeps the P2 panel test setup and moves the P1 store inspector test onto it.
…aces

The Routes tab, get-routes and the Dashboard SSR and Analog fields
resolved the Analog app from the working directory, so in an Nx
workspace with several Analog apps they described the first app under
apps/ instead of the one Vite serves. They now share the Vite root
with the Analog tab through servedAnalogRoot().
Redacts the page URL and title in component tree reports, holds change
detection instances weakly, stops visibility reports after pagehide so
closed tabs are not counted as background tabs, points aria-controls at
the response preview only while it is open, focuses the URL pattern
after adding a rule, lets the panel find __connection.json next to
itself so the CLI Panel URL and a report served at / connect, keeps
refusing the folder the build was run from when --root is set, and
fixes the tool count in the tools docs.
Rebuilds extension/ui for the network inspector and base URL changes.
Brings in the Vite root fix for Analog routes and build meta, keeping the P2 server function names.
Decides the Back to latest focus from the finished restore response,
accepts pending select values on controls that update on blur or
submit, names the served Analog app in Nx workspaces, and marks
strings cut by the redaction window as truncated.
Rebuilds extension/ui for the store inspector focus change.
Brings in the second round of santoshyadavdev#184 review fixes and rebuilds extension/ui.
Brings in the squashed santoshyadavdev#184 and the santoshyadavdev#187 and santoshyadavdev#188 docs changes. P2 already held every santoshyadavdev#184 commit, so the conflicts keep this branch's side.
@erkamyaman
erkamyaman merged commit e3d635c into santoshyadavdev:main Sep 30, 2026
6 checks passed
erkamyaman added a commit to erkamyaman/angular-devtools that referenced this pull request Sep 30, 2026
Brings in the squashed santoshyadavdev#184 and santoshyadavdev#185 and the santoshyadavdev#187 and santoshyadavdev#188 docs changes. This branch already held every santoshyadavdev#184 and santoshyadavdev#185 commit, so the conflicts keep this branch's side.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: agents MCP server, agent tools and resources area: ci Workflows, hooks and repository tooling area: demo The demo apps area: docs The documentation site area: extension The Chrome extension area: package The ng-devtools package (packages/ng-devtools) area: panel The devtools panel app (app/)

Projects

None yet

1 participant